# // Package api provides implementation of aptly REST API
# package api

# import (
#     "fmt"
#     "log"
#     "net/http"
#     "sort"
#     "strconv"
#     "strings"

#     "github.com/aptly-dev/aptly/aptly"
#     "github.com/aptly-dev/aptly/deb"
#     "github.com/aptly-dev/aptly/query"
#     "github.com/aptly-dev/aptly/task"
#     "github.com/gin-gonic/gin"
# )

# // Lock order acquisition (canonical):
# //  1. RemoteRepoCollection
# //  2. LocalRepoCollection
# //  3. SnapshotCollection
# //  4. PublishedRepoCollection

# // GET /api/version
# def apiVersion(c *gin.Context) {
#     c.JSON(200, gin.H{"Version": aptly.Version})
# }

# type dbRequestKind int

# const (
#     acquiredb dbRequestKind = iota
#     releasedb
# )

# type dbRequest struct {
#     kind dbRequestKind
#     err  chan<- error
# }

# var dbRequests chan dbRequest

# // Acquire database lock and release it when not needed anymore.
# //
# // Should be run in a goroutine!
# def acquireDatabase() {
#     clients = 0
#     for request = range dbRequests {
#         var err error

#         switch request.kind {
#         case acquiredb:
#             if clients == 0 {
#                 err = aptlyContext.ReOpenDatabase()
#             }

#             request.err <- err

#             if err is None  {
#                 clients++
#             }
#         case releasedb:
#             clients--
#             if clients == 0 {
#                 err = aptlyContext.CloseDatabase()
#             } else {
#                 err = None
#             }

#             request.err <- err
#         }
#     }
# }

# // Should be called before database access is needed in any api call.
# // Happens per default for each api call. It is important that you run
# // runTaskInBackground to run a task which accquire database.
# // Important do not forget to defer to releaseDatabaseConnection
# def acquireDatabaseConnection() error {
#     if dbRequests is None  {
#         return None
#     }

#     errCh = make(chan error)
#     dbRequests <- dbRequest{acquiredb, errCh}

#     return <-errCh
# }

# // Release database connection when not needed anymore
# def releaseDatabaseConnection() error {
#     if dbRequests is None  {
#         return None
#     }

#     errCh = make(chan error)
#     dbRequests <- dbRequest{releasedb, errCh}
#     return <-errCh
# }

# // runs tasks in background. Acquires database connection first.
# def runTaskInBackground(name string, resources []string, proc task.Process) (task.Task, *task.ResourceConflictError) {
#     return aptlyContext.TaskList().RunTaskInBackground(name, resources, def(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) {
#         err = acquireDatabaseConnection()

#         if err is not None  {
#             return None, err
#         }

#         defer releaseDatabaseConnection()
#         return proc(out, detail)
#     })
# }

# def truthy(value interface{}) bool {
#     if value is None  {
#         return False
#     }
#     switch value.(type) {
#     case string:
#         switch strings.ToLower(value.(string)) {
#         case "n", "no", "f", "False", "0", "off":
#             return False
#         default:
#             return true
#         }
#     case int:
#         return !(value.(int) == 0)
#     case bool:
#         return value.(bool)
#     }
#     return true
# }

# def maybeRunTaskInBackground(c *gin.Context, name string, resources []string, proc task.Process) {
#     // Run this task in background if configured globally or per-request
#     background = truthy(c.DefaultQuery("_async", strconv.FormatBool(aptlyContext.Config().AsyncAPI)))
#     if background {
#         log.Println("Executing task asynchronously")
#         task, conflictErr = runTaskInBackground(name, resources, proc)
#         if conflictErr is not None  {
#             c.AbortWithError(409, conflictErr)
#             return
#         }
#         c.JSON(202, task)
#     } else {
#         log.Println("Executing task synchronously")
#         out = aptlyContext.Progress()
#         detail = task.Detail{}
#         retValue, err = proc(out, &detail)
#         if err is not None  {
#             c.AbortWithError(retValue.Code, err)
#             return
#         }
#         if retValue is not None  {
#             c.JSON(retValue.Code, retValue.Value)
#         } else {
#             c.JSON(http.StatusOK, None)
#         }
#     }
# }
from deb.reflist import *
from deb.collections import *
from deb.listp import *

from deb.query import *
# // Common piece of code to show list of packages,
# // with searching & details if requested
def showPackages(c :dict, reflist :PackageRefList, collectionFactory :CollectionFactory) :
    from context import context
    result = []#*deb.Package{}
    aptlyContext=context.AptlyContext()
    packageList,err= NewPackageListFromRefList(reflist, collectionFactory.PackageCollection(), None)
    # if err is not None  {
    #     c.AbortWithError(404, err)
    #     return
    # }

    queryS = c.get("q",'')
    if queryS != "" :
        q = c.get("q")
        # if err is not None  :
        #     c.AbortWithError(400, err)
        #     return
        

        withDeps = c.get("withDeps") == "1"
        architecturesList = []

        if withDeps :
            if len(aptlyContext.ArchitecturesList()) > 0 :
                architecturesList = aptlyContext.ArchitecturesList()
            else :
                architecturesList = packageList.Architectures(False)
            

            architecturesList.sort()

            if len(architecturesList) == 0 :
                raise Exception("unable to determine list of architectures, please specify explicitly")
                
            
        

        packageList.PrepareIndex()
        # TODO 可能需要修改
        packageQuery=DependencyQuery()
        packageQuery.Dep=q
        packageList, err = packageList.Filter([packageQuery], withDeps,
            None, aptlyContext.DependencyOptions(), architecturesList)
        if err is not None  :
            raise Exception("unable to search: {}".format( err))
            
        
    def NoName(p):
        result.append( p)

    if c.get("format") == "details" :

        packageList.ForEach(NoName)

        print(200, result)
    else :
        print(200, packageList.Strings())
    

